package com.liaowei.user.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.digest.BCrypt;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.liaowei.common.BaseResponse;
import com.liaowei.common.Constants;
import com.liaowei.common.ErrorCode;
import com.liaowei.exception.CustomerException;
import com.liaowei.model.domain.Tag;
import com.liaowei.model.domain.User;
import com.liaowei.model.domain.UserFan;
import com.liaowei.model.domain.UserTag;
import com.liaowei.model.param.ModifyPasswordParam;
import com.liaowei.model.param.SignupUserParam;
import com.liaowei.model.vo.UserVO;
import com.liaowei.user.mapper.*;
import com.liaowei.user.model.param.PageUserParam;
import com.liaowei.user.model.param.UserParam;
import com.liaowei.user.openfeign.ArticleClient;
import com.liaowei.user.openfeign.PostClient;
import com.liaowei.user.openfeign.TagClient;
import com.liaowei.user.service.UserService;
import com.liaowei.user.service.UserTagService;
import com.liaowei.util.PasswordUtils;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author LindaMan
 * @description 针对表【wy_user(用户表)】的数据库操作Service实现
 * @createDate 2023-05-01 17:19:40
 */
@Service
@RequiredArgsConstructor
public class UserServiceImpl extends ServiceImpl<UserMapper, User>
        implements UserService {

    private final String roleName = "user"; // 普通用户具有的角色
    private final String[] permissionNames = {"comment"}; // 普通用户具有的权限
    private final UserMapper userMapper;
    private final RoleMapper roleMapper;
    private final PermissionMapper permissionMapper;
    private final UserRoleMapper userRoleMapper;
    private final UserPermissionMapper userPermissionMapper;
    private final UserTagService userTagService;
    private final UserFanMapper userFanMapper;
    private final TagClient tagClient;
    private final ArticleClient articleClient;
    private final PostClient postClient;


    // 转换UserVO
    public UserVO convertUserToUserVO(User user) {
        // 复制脱敏
        UserVO userVO = new UserVO();
        BeanUtil.copyProperties(user, userVO, "password");

        // 封装其他属性
        // fanNum
        long fanNum = userFanMapper.
                selectCount(Wrappers.lambdaQuery(UserFan.class).eq(UserFan::getUserId, user.getId()));
        userVO.setFanNum(fanNum);

        // tagList
        List<UserTag> userTagList = userTagService
                .list(Wrappers.lambdaQuery(UserTag.class).eq(UserTag::getUserId, user.getId()));
        List<Long> tagIdList = userTagList.stream().map(UserTag::getTagId).collect(Collectors.toList());
        BaseResponse<List<Tag>> tagResponse = tagClient.tagList(tagIdList);
        if (tagResponse.getCode() == 1) {
            userVO.setTagList(tagResponse.getData());
        }

        // articleNum
        BaseResponse<Long> articleResponse = articleClient.countOfArticleByUserId(user.getId());
        if (articleResponse.getCode() == 1) {
            userVO.setArticleNum(articleResponse.getData());
        }

        // postNum
        BaseResponse<Long> postResponse = postClient.countOfPostByUserId(user.getId());
        if (postResponse.getCode() == 1) {
            userVO.setPostNum(postResponse.getData());
        }

        return userVO;
    }


    /**
     * 根据昵称分页查询用户列表
     * @param nickname  昵称
     * @param pageNum 当前页
     * @param pageSize 分页大小
     * @return IPage<User>
     */
    @Override
    public IPage<User> searchPageUserListByNickname(String nickname, int pageNum, int pageSize) {
        // 构造分页构造器
        IPage<User> page = new Page<>(pageNum,pageSize);

        // 构造查询构造器
        LambdaQueryWrapper<User> wrapper = Wrappers.lambdaQuery(User.class).like(User::getNickname, nickname);

        // 分页查询
        userMapper.selectPage(page,wrapper);

        return page;
    }

    /**
     * 修改密码
     * @param passwordParam 密码参数
     * @return 提示信息
     */
    @Override
    public String modifyPassword(ModifyPasswordParam passwordParam) {
        // 判断是否登录
        Long loginId = StpUtil.getLoginIdAsLong();
        if (BeanUtil.isEmpty(loginId)){
            throw new CustomerException(ErrorCode.PARAMS_ERROR);
        }

        // 检验旧密码是否正确
        User user = userMapper.selectById(loginId);
        String originPassword = user.getPassword();
        String oldPassword = passwordParam.getOldPassword();
        if (!BCrypt.checkpw(oldPassword,originPassword)){
            throw new CustomerException(Constants.PASSWORD_NOT_MATCH,"密码输入不正确");
        }

        // 判断两次输入密码是否一致
        String checkPassword = passwordParam.getCheckPassword();
        String newPassword = passwordParam.getNewPassword();
        PasswordUtils.matchPassword(checkPassword,newPassword);

        // 判断新密码是否和原始密码一致
        if (BCrypt.checkpw(newPassword,originPassword)){
            throw new CustomerException(Constants.EQUAL_PASSWORD,"新密码不能与原始密码一致");
        }

        // 修改密码
        user.setPassword(PasswordUtils.bcryptPassword(newPassword));
        try {
            userMapper.updateById(user);
        } catch (Exception e) {
            throw new CustomerException(ErrorCode.SYSTEM_ERROR);
        }

        // 退出登录
        StpUtil.logout(loginId);

        return "修改成功";
    }

    /**
     * 用户退出
     * @return 提示信息
     */
    @Override
    public String logout() {
        // 判断是否登录
        Long loginId = StpUtil.getLoginIdAsLong();
        if (BeanUtil.isEmpty(loginId)){
            throw new CustomerException(ErrorCode.PARAMS_ERROR);
        }

        // 退出
        try {
            StpUtil.logout(loginId);
        } catch (Exception e) {
            throw new CustomerException(ErrorCode.SYSTEM_ERROR);
        }

        return "退出成功";
    }

    /**
     * 根据用户id查询用户信息
     *
     * @param userId 用户id
     * @return UserVO
     */
    @Override
    public UserVO searchByUserId(Long userId) {
        // 判断用户是否存在
        User user = userMapper.selectById(userId);
        if (BeanUtil.isEmpty(user))
            throw new CustomerException(Constants.PARAM_ERROR, "未查询到合法用户");

        // 返回结果
        return convertUserToUserVO(user);
    }

    /**
     * 修改用户信息
     *
     * @param userParam 用户修改参数
     * @return 用户信息
     */
    @Transactional
    @Override
    public String modify(UserParam userParam) {
        // 从redis中获取自己的用户id
        long loginId = Long.parseLong(StpUtil.getLoginId().toString());

        // 封装user
        User user = new User();
        user.setId(loginId);
        user.setNickname(userParam.getNickname());
        user.setAvatar(userParam.getAvatar());
        user.setEmail(userParam.getEmail());
        user.setDescription(userParam.getDescription());

        // 保存兴趣标签
        List<Long> tagIdList = userParam.getTagIdList();
        if (BeanUtil.isNotEmpty(tagIdList)) {
            // 检查标签是否存在
            BaseResponse<Integer> response = tagClient.countTagByIds(tagIdList);
            Integer count = response.getData();
            if (count != tagIdList.size()) {
                throw new CustomerException(Constants.PARAM_ERROR, "无效标签");
            }

            try {
                // 先删除原来的标签
                LambdaUpdateWrapper<UserTag> userIdWrapper = Wrappers.lambdaUpdate(UserTag.class)
                        .eq(UserTag::getUserId, userParam.getId());
                userTagService.remove(userIdWrapper);

                // 新增标签
                List<UserTag> userTagList = tagIdList.stream().map(tagId -> {
                    UserTag userTag = new UserTag();
                    userTag.setUserId(userParam.getId());
                    userTag.setTagId(tagId);
                    userTag.setUpdateTime(new Date());

                    return userTag;
                }).collect(Collectors.toList());
                userTagService.saveBatch(userTagList);
            } catch (Exception e) {
                throw new CustomerException(ErrorCode.SYSTEM_ERROR);
            }
        }
        try {
            // 修改用户
            userMapper.updateById(user);
        } catch (Exception e) {
            throw new CustomerException(ErrorCode.SYSTEM_ERROR);
        }

        return "保存成功";
    }

    /**
     * 后台管理-分页查询
     *
     * @param pageUserParam 用户分页参数
     * @return 用户分页信息
     */
    @Override
    public IPage<UserVO> pageList(PageUserParam pageUserParam) {
        // 构造查询构造器
        LambdaQueryWrapper<User> pageUserWrapper = Wrappers.lambdaQuery(User.class)
                .eq(StrUtil.isNotBlank(pageUserParam.getUsername()), User::getUsername, pageUserParam.getUsername())
                .like(User::getNickname, pageUserParam.getNickname())
                .eq(StrUtil.isNotBlank(pageUserParam.getEmail()), User::getEmail, pageUserParam.getEmail())
                .ge(BeanUtil.isNotEmpty(pageUserParam.getStartJoinTime()),User::getCreateTime,pageUserParam.getStartJoinTime())
                .le(BeanUtil.isNotEmpty(pageUserParam.getEndJoinTime()),User::getCreateTime,pageUserParam.getEndJoinTime())
                .orderByDesc(User::getCreateTime);

        // 构造分页构造器
        IPage<User> page = new Page<>(pageUserParam.getPageParam().getPageNum(),
                pageUserParam.getPageParam().getPageSize());
        // 分页查询
        userMapper.selectPage(page, pageUserWrapper);

        // 封装UserVO
        IPage<UserVO> pageUserVO = new Page<>();
        BeanUtil.copyProperties(page, pageUserVO, "records");
        // 封装records
        List<UserVO> userVORecords = page.getRecords().stream().map(this::convertUserToUserVO)
                .collect(Collectors.toList());
        pageUserVO.setRecords(userVORecords);

        // 返回结果
        return pageUserVO;
    }


    /**
     * 用户注册
     *
     * @param signupUserParam 用户注册参数
     * @return 注册成功提示信息
     */
    @Transactional
    @Override
    public String signup(SignupUserParam signupUserParam) {
        // 封装user
        User user = new User();
        BeanUtil.copyProperties(signupUserParam, user, "checkPassword"); // 不复制第二次输入的密码

        // 密码处理
        user.setPassword(PasswordUtils.bcryptPassword(user.getPassword()));
        // 新增用户
        userMapper.insert(user); // 全局捕获唯一约束异常

        try {
            // 获取用户id
            Long userId = user.getId();

            // 为用户添加角色和权限
            // 查询对应角色id
            long roleId = roleMapper.selectIdByName(roleName);
            // 查询对应权限id
            long[] permissionIds = permissionMapper.selectIdsByName(permissionNames);
            // 插入数据
            userRoleMapper.insertUserRole(userId, roleId);
            userPermissionMapper.insertBatchByUserId(userId, permissionIds);

        } catch (Exception e) {
            throw new CustomerException(Constants.SYSTEM_ERROR, "注册失败，请稍后重试");
        }

        return "注册成功";
    }

}




